﻿using gt.rediscache.core.Entry;
using gt.rediscache.core.Utility;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace gt.rediscache.core.Clients
{
    public partial class RedisClient
    {
        /// <summary>
        /// 设置hash key field value
        /// true field is newen
        /// false field is updated
        /// </summary>
        public bool HashSet(string key, string field, string value, TimeSpan? expiredTime = null, When when = When.Always, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashSetMessage(key, field, value, when);
            bool flag = Execute(RedisCommand.HashSet, message, flags).BoolResult;
            if (expiredTime != null)
                KeyExpired(key, expiredTime.Value);
            return flag;
        }
        /// <summary>
        /// 设置hash key 批量field value
        /// 注：如果values很大，请分批Set
        /// true field is new
        /// false field is updated
        /// </summary>
        public void HashSet(string key, Dictionary<string, string> values, TimeSpan? expiredTime = null, CommandFlags flags = CommandFlags.None)
        {
            if (values == null || values.Count == 0) return;
            HashEntry[] entries = RedisValueConverter.Convert(values);
            var message = new HashSetArrayMessage(key, entries);
            Execute(RedisCommand.HashSetArray, message, flags);
            if (expiredTime != null)
                KeyExpired(key, expiredTime.Value);
        }
        /// <summary>
        /// 获取hash所有 field-value 值
        /// 注：如果hash内数据量很大，请使用 hashscan 方法
        /// </summary>
        public Dictionary<string, string> HashGetAll(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashGetAllMessage(key);
            var entries = Execute(RedisCommand.HashGetAll, message, flags).HashEntryArrayResult;
            return RedisValueConverter.Convert(entries);
        }
        /// <summary>
        /// 获取hash key field-value值
        /// </summary>
        public string HashGet(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashGetMessage(key, field);
            return Execute(RedisCommand.HashGet, message, flags).RedisValueResult;
        }
        /// <summary>
        /// Hash field是否存在
        /// </summary>
        public bool HashExists(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashExistsMessage(key, field);
            return Execute(RedisCommand.HashExist, message, flags).BoolResult;
        }
        /// <summary>
        /// 删除hash key field-value值
        /// </summary>
        public bool HashRemove(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashRemoveMessage(key, field);
            return Execute(RedisCommand.HashRemove, message, flags).BoolResult;
        }
        /// <summary>
        /// 批量删除hash key field-value值
        /// 注：如果fields很大，请分批删除
        /// </summary>
        public long HashRemove(string key, string[] fields, CommandFlags flags = CommandFlags.None)
        {
            var hashFields = RedisValueConverter.Convert(fields);
            var message = new HashRemoveArrayMessage(key, hashFields);
            return Execute(RedisCommand.HashRemoveArray, message, flags).LongResult;
        }
        /// <summary>
        /// 原子性 hash value 增长
        /// </summary>
        public long HashIncrement(string key, string field, TimeSpan? expiredTime = null, long inc = 1, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashIncrementMessage(key, field, inc);
            long flag = Execute(RedisCommand.HashIncrement, message, flags).LongResult;
            if (expiredTime != null)
            {
                KeyExpired(key, expiredTime.Value);
            }
            return flag;
        }
        /// <summary>
        /// hash 遍历
        /// 适用于hash存有大量数据
        /// </summary>
        public IEnumerable<HashEntry> HashScan(string key, string fieldPattern, int pageSize = 10, long cursor = 0, int pageOffset = 0, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashScanMessage(key, fieldPattern, pageSize, cursor, pageOffset);
            return Execute(RedisCommand.HashScan, message, flags).HashEntryScanValue;
        }
        /// <summary>
        /// 获取hash所有的field
        /// 注：如果hash内数据量很大，请使用 hashscan 方法
        /// </summary>
        public string[] HashFields(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashFieldsMessage(key);
            var result = Execute(RedisCommand.HashFields, message, flags).RedisValueArrayResult;
            return RedisValueConverter.Convert(result);
        }
        /// <summary>
        /// 获取hash所有的value
        /// 注：如果hash内数据量很大，请使用 hashscan 方法
        /// </summary>
        public string[] HashValues(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashValuesMessage(key);
            var result = Execute(RedisCommand.HashValues, message, flags).RedisValueArrayResult;
            return RedisValueConverter.Convert(result);
        }
        /// <summary>
        /// 获取hash长度
        /// </summary>
        public long HashLength(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashLengthMessage(key);
            return Execute(RedisCommand.HashLength, message, flags).LongResult;
        }


        #region Async

        public async Task<bool> HashSetAsync(string key, string field, string value, TimeSpan? expiredTime = null, CommandFlags flags = CommandFlags.None, When when = When.Always)
        {
            var message = new HashSetMessage(key, field, value, when);
            return await ExecuteAsync(RedisCommand.HashSet, message, flags).ContinueWith((task) =>
            {
                var result = task.Result.BoolResult;
                if (expiredTime != null)
                    KeyExpired(key, expiredTime.Value);
                return result;
            }).ConfigureAwait(false);
        }

        public async Task<bool> HashSetAsync(string key, Dictionary<string, string> values, TimeSpan? expiredTime = null, CommandFlags flags = CommandFlags.None)
        {
            var entries = RedisValueConverter.Convert(values);
            if (entries == null || entries.Length == 0) return false;

            var message = new HashSetArrayMessage(key, entries);
            return await ExecuteAsync(RedisCommand.HashSetArray, message, flags).ContinueWith(t =>
            {
                if (expiredTime != null)
                    KeyExpired(key, expiredTime.Value);
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<Dictionary<string, string>> HashGetAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashGetAllMessage(key);
            return await ExecuteAsync(RedisCommand.HashGetAll, message, flags).ContinueWith((task) =>
            {
                var result = task.Result.HashEntryArrayResult;
                return RedisValueConverter.Convert(result);
            }).ConfigureAwait(false);
        }

        public async Task<string> HashGetAsync(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashGetMessage(key, field);
            return await ExecuteAsync(RedisCommand.HashGet, message, flags).ContinueWith(t =>
            {
                return t.Result.RedisValueResult;
            }).ConfigureAwait(false);
        }

        public async Task<bool> HashExistsAsync(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashExistsMessage(key, field);
            return await ExecuteAsync(RedisCommand.HashExist, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<bool> HashRemoveAsync(string key, string field, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashRemoveMessage(key, field);
            return await ExecuteAsync(RedisCommand.HashRemove, message, flags).ContinueWith(t =>
            {
                return t.Result.BoolResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> HashRemoveAsync(string key, string[] fields, CommandFlags flags = CommandFlags.None)
        {
            var values = RedisValueConverter.Convert(fields);
            if (values == null || values.Length == 0) return await Task.FromResult<long>(0);
            var message = new HashRemoveArrayMessage(key, values);
            return await ExecuteAsync(RedisCommand.HashRemoveArray, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        public async Task<long> HashIncrementAsync(string key, string field, TimeSpan? expiredTime = null, long inc = 1, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashIncrementMessage(key, field, inc);
            return await ExecuteAsync(RedisCommand.HashIncrement, message, flags).ContinueWith((task) =>
            {
                var result = task.Result.LongResult;
                if (expiredTime != null) KeyExpired(key, expiredTime.Value);
                return result;
            }).ConfigureAwait(false);
        }

        public async Task<string[]> HashFieldsAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashFieldsMessage(key);
            return await ExecuteAsync(RedisCommand.HashFields, message, flags).ContinueWith((task) =>
            {
                return RedisValueConverter.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);
        }

        public async Task<string[]> HashValuesAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashValuesMessage(key);
            message.Key = key;
            return await ExecuteAsync(RedisCommand.HashValues, message, flags).ContinueWith((task) =>
            {
                return RedisValueConverter.Convert(task.Result.RedisValueArrayResult);
            }).ConfigureAwait(false);
        }

        public async Task<long> HashLengthAsync(string key, CommandFlags flags = CommandFlags.None)
        {
            var message = new HashLengthMessage(key);
            message.Key = key;
            return await ExecuteAsync(RedisCommand.HashLength, message, flags).ContinueWith(t =>
            {
                return t.Result.LongResult;
            }).ConfigureAwait(false);
        }

        #endregion

    }
}
